En omfattende guide til å bygge en frontend hendelseslytter for blokkjedens smartkontrakter, for sanntidsovervåking av endringer i kontraktstilstand. Lær å integrere Web3.js eller ethers.js, dekode hendelsesdata og oppdatere applikasjonens brukergrensesnitt.
Frontend Hendelseslytter for Blokkjedens Smartkontrakter: Overvåking av Kontraktstilstand
Desentraliserte applikasjoner (DApps) krever ofte sanntidsoppdateringer for å reflektere endringer i den underliggende smartkontraktens tilstand. Det er her hendelseslyttere kommer inn i bildet. Ved å overvåke hendelser som utstedes av smartkontrakter, kan frontend-applikasjoner reagere på tilstandsoverganger og gi brukere oppdatert informasjon. Denne guiden gir en omfattende oversikt over hvordan man bygger en frontend hendelseslytter for blokkjedens smartkontrakter, med fokus på praktisk implementering og beste praksis.
Hva er Smartkontrakt-hendelser?
Smartkontrakter, skrevet i språk som Solidity, kan utstede hendelser (emit events) når spesifikke handlinger skjer i kontrakten. Disse hendelsene fungerer som en varslingsmekanisme, som signaliserer til eksterne applikasjoner at en tilstandsendring har funnet sted. Tenk på dem som loggoppføringer som permanent lagres på blokkjeden. Hendelser inneholder informasjon om endringen, noe som gjør at applikasjoner kan reagere deretter.
For eksempel, tenk på en enkel token-kontrakt. Den kan utstede en hendelse når tokens overføres mellom kontoer. Denne hendelsen vil typisk inkludere avsenderens adresse, mottakerens adresse og beløpet som ble overført. En frontend-applikasjon kan lytte etter denne hendelsen og oppdatere brukerens saldo i sanntid.
Hvorfor bruke Hendelseslyttere?
Å polle blokkjeden for tilstandsendringer er ineffektivt og ressurskrevende. Hendelseslyttere gir en mer elegant og effektiv løsning ved å la applikasjoner passivt vente på varsler. Dette reduserer belastningen på blokkjeden og forbedrer responsen til DApp-en.
Viktige fordeler med å bruke hendelseslyttere inkluderer:
- Sanntidsoppdateringer: Gi brukere umiddelbar tilbakemelding på endringer i kontraktstilstanden.
- Forbedret Effektivitet: Reduser behovet for konstant polling av blokkjeden.
- Forbedret Brukeropplevelse: Skap en mer dynamisk og responsiv applikasjon.
- Reduserte Gasskostnader: Unngå unødvendige leseoperasjoner på blokkjeden.
Verktøy og Teknologier
Flere verktøy og biblioteker kan brukes til å bygge frontend hendelseslyttere. De mest populære alternativene inkluderer:
- Web3.js: Et JavaScript-bibliotek som lar deg interagere med Ethereum-noder og smartkontrakter. Det gir et omfattende API for å få tilgang til blokkjededata, sende transaksjoner og lytte etter hendelser.
- Ethers.js: Et annet populært JavaScript-bibliotek for å interagere med Ethereum. Det er kjent for sin enkelhet, sikkerhet og ytelse.
- Infura/Alchemy: Infrastrukturleverandører som tilbyr pålitelig tilgang til Ethereum-nettverket. De gir API-er for å lese blokkjededata og sende transaksjoner, noe som eliminerer behovet for å kjøre din egen Ethereum-node.
- WebSockets: En kommunikasjonsprotokoll som muliggjør sanntids, toveis kommunikasjon mellom en klient og en server. WebSockets brukes ofte for å levere hendelsesvarsler til frontenden.
Bygge en Frontend Hendelseslytter: En Steg-for-Steg Guide
Denne delen skisserer trinnene for å bygge en frontend hendelseslytter ved hjelp av Web3.js eller ethers.js.
Steg 1: Sette opp Utviklingsmiljøet Ditt
Før du begynner, sørg for at du har følgende installert:
- Node.js: Et JavaScript-kjøremiljø.
- npm (Node Package Manager) eller yarn: En pakkebehandler for å installere avhengigheter.
- En kodeeditor: Visual Studio Code, Sublime Text, eller en annen editor du foretrekker.
Opprett en ny prosjektmappe og initialiser den med npm eller yarn:
mkdir my-dapp
cd my-dapp
npm init -y
Eller ved å bruke yarn:
mkdir my-dapp
cd my-dapp
yarn init -y
Steg 2: Installere Avhengigheter
Installer Web3.js eller ethers.js, sammen med eventuelle andre nødvendige avhengigheter. For eksempel kan du trenge et bibliotek for å håndtere miljøvariabler.
Ved å bruke npm:
npm install web3 dotenv
Ved å bruke yarn:
yarn add web3 dotenv
Eller for ethers.js:
Ved å bruke npm:
npm install ethers dotenv
Ved å bruke yarn:
yarn add ethers dotenv
Steg 3: Konfigurere din Web3 Provider
Du må konfigurere en Web3-provider for å koble til Ethereum-nettverket. Dette kan gjøres ved hjelp av Infura, Alchemy, eller en lokal Ethereum-node (som Ganache).
Opprett en `.env`-fil i prosjektmappen din og legg til din Infura- eller Alchemy-API-nøkkel:
INFURA_API_KEY=DIN_INFURA_API_NØKKEL
Deretter, i JavaScript-filen din, konfigurerer du Web3-provideren:
Ved å bruke Web3.js:
require('dotenv').config();
const Web3 = require('web3');
const infuraApiKey = process.env.INFURA_API_KEY;
const web3 = new Web3(new Web3.providers.WebsocketProvider(`wss://mainnet.infura.io/ws/v3/${infuraApiKey}`));
Ved å bruke ethers.js:
require('dotenv').config();
const { ethers } = require('ethers');
const infuraApiKey = process.env.INFURA_API_KEY;
const provider = new ethers.providers.WebSocketProvider(`wss://mainnet.infura.io/ws/v3/${infuraApiKey}`);
Merk: Erstatt `mainnet` med det aktuelle nettverket (f.eks. `ropsten`, `rinkeby`, `goerli`) hvis du bruker et testnettverk.
Steg 4: Hente Kontraktens ABI og Adresse
For å interagere med smartkontrakten din, trenger du dens Application Binary Interface (ABI) og adresse. ABI er en JSON-fil som beskriver kontraktens funksjoner og hendelser. Adressen er kontraktens plassering på blokkjeden.
Du kan hente ABI-en fra Solidity-kompilatorens utdata. Adressen vil bli vist etter at du har deployert kontrakten.
Lagre ABI-en i en JSON-fil (f.eks. `MinKontrakt.json`) og adressen i `.env`-filen din:
CONTRACT_ADDRESS=0xDinKontraktadresse...
Steg 5: Opprette en Kontrakt-instans
Bruk ABI-en og adressen til å opprette en kontrakt-instans i JavaScript-filen din:
Ved å bruke Web3.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MinKontrakt.json').abi;
const minKontrakt = new web3.eth.Contract(contractABI, contractAddress);
Ved å bruke ethers.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MinKontrakt.json').abi;
const minKontrakt = new ethers.Contract(contractAddress, contractABI, provider);
Steg 6: Lytte etter Hendelser
Nå kan du begynne å lytte etter hendelser som utstedes av smartkontrakten din. Bruk `events`-egenskapen til kontrakt-instansen din for å abonnere på hendelser.
Ved å bruke Web3.js:
minKontrakt.events.MinHendelse({
filter: {minIndekserteParam: [20,23]}, // Valgfritt filter ved bruk av indekserte parametere.
fromBlock: 'latest' // Begynn å lytte fra den siste blokken.
}, function(error, event){
if(!error)
{console.log(event);}
else
{console.log(error);}
})
.on('data', function(event){
console.log(event);
})
.on('changed', function(event){
// fjern hendelse fra lokal database
})
.on('error', console.error);
Eller, ved å bruke async/await:
minKontrakt.events.MinHendelse({
filter: {minIndekserteParam: [20,23]}, // Valgfritt filter ved bruk av indekserte parametere.
fromBlock: 'latest' // Begynn å lytte fra den siste blokken.
})
.on('data', async function(event){
console.log(event);
// Behandle hendelsesdataene her, f.eks. oppdatere UI
try {
// Eksempel: Interager med en annen del av din DApp.
// await enAnnenFunksjon(event.returnValues);
} catch (error) {
console.error("Feil ved behandling av hendelse:", error);
}
})
.on('changed', function(event){
// fjern hendelse fra lokal database
})
.on('error', console.error);
Ved å bruke ethers.js:
minKontrakt.on("MinHendelse", (param1, param2, event) => {
console.log("Hendelsen MinHendelse ble utstedt!");
console.log("Param1:", param1);
console.log("Param2:", param2);
console.log("Hendelsesdata:", event);
// Behandle hendelsesdataene her, f.eks. oppdatere UI
});
I begge eksemplene, erstatt `MinHendelse` med navnet på hendelsen du vil lytte etter. Tilbakekallingsfunksjonen vil bli utført hver gang hendelsen utstedes. Du kan få tilgang til hendelsesdataene gjennom `event`-objektet.
Steg 7: Håndtere Hendelsesdata
`event`-objektet inneholder informasjon om hendelsen, inkludert argumentene som ble sendt til den, blokknummeret og transaksjons-hashen. Du kan bruke disse dataene til å oppdatere applikasjonens UI eller utføre andre handlinger.
For eksempel, hvis hendelsen din inkluderer en brukers saldo, kan du oppdatere saldovisningen i frontenden:
// Inne i hendelseshåndtereren
const saldo = event.returnValues.balance; // Web3.js
// Eller
// const saldo = param1; // ethers.js, forutsatt at param1 er saldoen
document.getElementById('balance').textContent = saldo;
Avanserte Teknikker for Hendelseslyttere
Denne delen utforsker noen avanserte teknikker for å bygge mer sofistikerte hendelseslyttere.
Filtrere Hendelser
Du kan filtrere hendelser basert på spesifikke kriterier, som verdien av en indeksert parameter. Dette kan hjelpe deg med å begrense hendelsene du er interessert i og redusere mengden data du må behandle.
I Web3.js kan du bruke `filter`-alternativet når du abonnerer på hendelser:
minKontrakt.events.MinHendelse({
filter: {minIndekserteParam: [20, 23]}, // Lytt kun etter hendelser der minIndekserteParam er 20 eller 23.
fromBlock: 'latest'
}, function(error, event){
console.log(event);
})
I ethers.js kan du spesifisere filtre når du oppretter kontrakt-instansen eller når du legger til hendelseslytteren:
// Filtrer etter hendelsesnavn og indekserte argumenter
const filter = minKontrakt.filters.MinHendelse(arg1, arg2);
minKontrakt.on(filter, (arg1, arg2, event) => {
console.log("Hendelsen MinHendelse ble utstedt med spesifikke argumenter!");
console.log("Arg1:", arg1);
console.log("Arg2:", arg2);
console.log("Hendelsesdata:", event);
});
Lytte etter Tidligere Hendelser
Du kan hente tidligere hendelser som skjedde før hendelseslytteren din var aktiv. Dette kan være nyttig for å initialisere applikasjonens tilstand eller for revisjonsformål.
I Web3.js kan du bruke `getPastEvents`-metoden:
minKontrakt.getPastEvents('MinHendelse', {
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){
console.log(events);
});
I ethers.js kan du spørre hendelsesloggene ved å bruke providerens `getLogs`-metode:
const blokkNummer = await provider.getBlockNumber();
const filter = minKontrakt.filters.MinHendelse(arg1, arg2);
const logger = await provider.getLogs({
address: minKontrakt.address,
fromBlock: blokkNummer - 1000, // siste 1000 blokker
toBlock: blokkNummer,
topics: filter.topics // filter-emner
});
for (const log of logger) {
const parsetLogg = minKontrakt.interface.parseLog(log);
console.log(parsetLogg);
}
Håndtere Reverserte Transaksjoner
Transaksjoner kan noen ganger bli reversert på grunn av feil eller utilstrekkelig gass. Når en transaksjon reverseres, utstedes ikke hendelser knyttet til den transaksjonen. Det er viktig å håndtere reverserte transaksjoner elegant for å unngå uventet oppførsel i applikasjonen din.
En måte å håndtere reverserte transaksjoner på er å overvåke transaksjonskvitteringen. Kvitteringen inneholder informasjon om transaksjonen, inkludert dens status (suksess eller feil). Hvis statusen er `0x0`, ble transaksjonen reversert.
Du kan bruke `web3.eth.getTransactionReceipt` (Web3.js) eller `provider.getTransactionReceipt` (ethers.js) metoden for å hente transaksjonskvitteringen.
Bruke WebSockets for Sanntidsoppdateringer
WebSockets gir en vedvarende forbindelse mellom klienten og serveren, noe som muliggjør sanntids, toveis kommunikasjon. Dette er ideelt for å levere hendelsesvarsler til frontenden.
Både Web3.js og ethers.js støtter WebSockets. For å bruke WebSockets, konfigurer din Web3-provider med et WebSocket-endepunkt (som vist i oppsettseksemplene ovenfor).
Sikkerhetshensyn
Når du bygger frontend hendelseslyttere, er det viktig å vurdere følgende sikkerhetsaspekter:
- Datavalidering: Valider alltid hendelsesdata før du bruker dem i applikasjonen din. Ikke stol blindt på dataene som mottas fra blokkjeden.
- Feilhåndtering: Implementer robust feilhåndtering for å forhindre uventet oppførsel og potensielle sikkerhetssårbarheter.
- Rate Limiting: Implementer rate limiting for å forhindre misbruk og beskytte applikasjonen din mot denial-of-service-angrep.
- Avhengighetsstyring: Hold avhengighetene dine oppdatert for å tette sikkerhetshull.
- Sanering av Brukerinput: Hvis du viser hendelsesdata til brukere, saner dataene for å forhindre cross-site scripting (XSS)-angrep.
Beste Praksis
Følg disse beste praksisene for å bygge robuste og vedlikeholdbare frontend hendelseslyttere:
- Bruk en modulær arkitektur: Del applikasjonen din opp i mindre, gjenbrukbare komponenter.
- Skriv enhetstester: Test hendelseslytterne dine grundig for å sikre at de fungerer korrekt.
- Bruk et loggføringsrammeverk: Loggfør viktige hendelser og feil for å hjelpe deg med å feilsøke applikasjonen din.
- Dokumenter koden din: Dokumenter koden din tydelig for å gjøre den enklere å forstå og vedlikeholde.
- Følg kodekonvensjoner: Følg konsistente kodekonvensjoner for å forbedre lesbarheten og vedlikeholdbarheten.
- Overvåk applikasjonen din: Overvåk applikasjonens ytelse og ressursbruk for å identifisere potensielle flaskehalser.
Eksempelscenario: Overvåke en Token-overføring
La oss se på et praktisk eksempel: overvåking av token-overføringer i en enkel ERC-20 token-kontrakt.
ERC-20-standarden inkluderer en `Transfer`-hendelse som utstedes hver gang tokens overføres mellom kontoer. Denne hendelsen inkluderer avsenderens adresse, mottakerens adresse og beløpet som ble overført.
Slik kan du lytte etter `Transfer`-hendelser i frontend-applikasjonen din:
Ved å bruke Web3.js:
minKontrakt.events.Transfer({
fromBlock: 'latest'
}, function(error, event){
if(!error)
{
console.log("Transfer-hendelse:", event);
const from = event.returnValues.from;
const to = event.returnValues.to;
const value = event.returnValues.value;
// Oppdater UI eller utfør andre handlinger
console.log(`Tokens overført fra ${from} til ${to}: ${value}`);
}
else
{console.error(error);}
});
Ved å bruke ethers.js:
minKontrakt.on("Transfer", (from, to, value, event) => {
console.log("Transfer-hendelse utstedt!");
console.log("Fra:", from);
console.log("Til:", to);
console.log("Verdi:", value.toString()); // Verdi er en BigNumber i ethers.js
console.log("Hendelsesdata:", event);
// Oppdater UI eller utfør andre handlinger
console.log(`Tokens overført fra ${from} til ${to}: ${value.toString()}`);
});
Dette kodeutdraget lytter etter `Transfer`-hendelser og logger avsenderens adresse, mottakerens adresse og beløpet som ble overført til konsollen. Du kan deretter bruke denne informasjonen til å oppdatere applikasjonens UI, vise transaksjonshistorikk eller utføre andre handlinger.
Konklusjon
Frontend hendelseslyttere for blokkjedens smartkontrakter er et kraftig verktøy for å bygge responsive DApps i sanntid. Ved å overvåke hendelser som utstedes av smartkontrakter, kan du gi brukere oppdatert informasjon og forbedre den generelle brukeropplevelsen. Denne guiden har dekket de grunnleggende konseptene, verktøyene og teknikkene for å bygge hendelseslyttere, sammen med avanserte emner som filtrering av hendelser, håndtering av reverserte transaksjoner og bruk av WebSockets for sanntidsoppdateringer. Ved å følge beste praksis som er skissert i denne guiden, kan du bygge robuste og sikre hendelseslyttere som vil forbedre funksjonaliteten og brukeropplevelsen til dine DApps.